package com.linkai.JUC._04_unsafecollection;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Description:  ArrayList，Vector，CopyOnWriteArrayList 区别
 *               ConcurrentModificationException 并发修改异常
 *
 *               CopyOnWriteArrayList参考：
 *                  https://www.cnblogs.com/dolphin0520/p/3938914.html
 * @Author: 林凯
 * @Date: 2021/10/24 13:40
 */
public class ListTest {
    public static void main(String[] args) {
        // 并发下 ArrayList 是不安全的
        /*
            解决方案：
            (1) 使用 Vector 解决
            (2) List<String> arrayList1 = Collections.synchronizedList(new ArrayList<>());
            (3) List<String> arrayList = new CopyOnWriteArrayList<>();
        * */

        List<String> arrayList = new ArrayList<>();
        LinkedList<String> linkedList = new LinkedList<>();
        /*
            ArrayList 和 LinkedList区别
            一个底层是数组实现，另一个底层是链表实现。
            ArrayList的插入操作涉及到元素的移动，而LinkedList的插入不涉及，所以综合来说LinkedList插入删除的效率高一些。
            查找效率的话肯定是ArrayList优于LinkedList（数组优于链表）
            同时LinkedList实现了Deque接口，所以 LinkedList 还可以当做队列来使用。

            扩充：
                都是线程不安全的，考虑使用 Vector，synchronizedList，CopyOnWriteArrayList
                顺便能扯到 synchronize 和 Lock 的区别

        * */

        List<String> vector = new Vector<>();
        List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());

        List<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();


        /*
            1. CopyOnWriteArrayList
                CopyOnWrite 写入时复制  COW   计算机程序设计领域的一种优化策略
                （1）多个线程调用的时候，list：读取的时候，固定的；写入（会导致覆盖）
                    CopyOnWrite：在写入的时候会复制一份，再写入（这个过程被加锁了，看源码）避免覆盖，造成数据问题！
                    add 方法里面的： newElements = Arrays.copyOf(elements, len + 1);
                （2）读写分离的思想
                （3）CopyOnWriteArrayList 比 Vector 优势在哪？
                    1. Vector 的 add 直接用 synchronize，CopyOnWriteArrayList 用 Lock
                    Vector 的曾删改查方法都加上了synchronized锁，保证同步的情况下，因为每个方法都要去获得锁，所以性能就会大大下降。
                    CopyOnWriteArrayList 方法只是在增删改方法上增加了ReentrantLock锁，但是他的读方法不加锁，
                    所以在读的方面就要比Vector性能要好
                （4）适用于读多写少的场景：白名单，黑名单，
                （5）数据一致性问题：只能保证数据的最终一致性，不能保证数据的实时一致性

        * */

        for (int i = 1; i <= 1000; i++) {
            new Thread(() -> {
                arrayList.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(arrayList);
            }, String.valueOf(i)).start();
        }

        while (Thread.activeCount() > 2) {
            // 除了main线程，和gc线程之外，还有线程在执行的话，就一直循环
            // 保证打印最后的长度的时候，其他线程已经执行完毕了。
        }
        System.out.println(arrayList.size());       // 线程安全的话，这里应该输出 100

    }
}
